"""
    This file is part of benjap.

    Copyright Graham Jones 2010.

    Benjap is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    banjap is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with benjap (COPYING file).  
    If not, see <http://www.gnu.org/licenses/>.

    $Id: appBase.py 37 2011-01-03 21:33:23Z grahamjones139 $
"""

import pygame
from pygame.locals import *
#QUIT, KEYDOWN, K_ESCAPE, MOUSEBUTTONDOWN, K_q, K_F4
import os

class appBase:
    """ appBase is the base application class on which all of the games
    in Benjamin's Application are based.
    It takes a parent, which is either another appBase instance or None.
    If it is None it initialises the screen, otherwise it stops the parent's
    main loop and uses the parent's screen.
    On exit it re-starts the parent's main loop.
    
    22Dec2010  GJ  ORIGINAL VERSION
    """
    def __init__(self,parent,fullscreen = True):
        """
        Initialises the following instance variables:
        self.parent - the parent application.
        self.screen - the screen used for drawing.
        self.running - flag to set the main loop running
        self.spriteList - list of active sprites.
        self.Sprites - rendergroup for sprites.
        """
        print "appBase.__init__()"
        if parent == None:
            print "no parent given - initialising screen"
            self.parent = None

            pygame.init()
            #pygame.display.init()
            pygame.mixer.init()
            # Start screen
            info = pygame.display.Info()
            screen_width = float(info.current_w)
            screen_height = float(info.current_h)

            screen_width = int(screen_width)
            screen_height = int(screen_height)
            self.screen_size = screen_width, screen_height
            if fullscreen:
                self.screen = pygame.display.set_mode(self.screen_size 
                                                      , HWSURFACE | 
                                                      DOUBLEBUF | 
                                                      FULLSCREEN
                                                      )
            else:
                self.screen = pygame.display.set_mode(self.screen_size 
                                                      , HWSURFACE | 
                                                      DOUBLEBUF                                                       )
            #self.screen = pygame.display.set_mode(self.screen_size)
            pygame.display.set_caption('benjAp')
            backButtonFile = "images/exit_button.png"
        else:
            self.parent = parent
            self.screen = parent.screen
            self.screen_size = parent.screen_size
            backButtonFile = "images/back_arrow.png"

        self.backButtonSize = 20
        backButtonSize = (self.backButtonSize,self.backButtonSize)
        self.backButton = pygame.image.load(backButtonFile)
        self.backButton = pygame.transform.smoothscale(self.backButton, 
                                                  backButtonSize).convert()
        self.backButtonRect = \
            self.backButton.get_rect(topleft=(
                self.screen_size[0]-self.backButtonSize, 
                self.screen_size[1]-self.backButtonSize
                ))
                                     


        self.timeScale = 1.0 # scale factor to accelerate or decelerate time.
        self.font18 = pygame.font.SysFont('arial', 18) #font to display text
        self.bg = pygame.Surface(self.screen_size)
        self.bg.fill((0,0,0)) # blank screen
        #self.screen.fill((0,0,0))
        self.drawBackground()
        self.Sprites = pygame.sprite.RenderUpdates()
        self.spriteList = []
        self.start()
        # end of __init__

    def start(self):
        """set the main loop running"""
        self.running = True

    def stop(self):
        """stop the main loop"""
        self.onStop()
        self.screen.blit(self.font18.render(
                ('Shutting Down'), 
                True, (255,255,255)), (0, 0))
        self.repaint()
        self.running = False
        if (self.parent != None):
            self.parent.drawBackground()

    def onStop(self):
        pass

    def drawBackButton(self):
        self.screen.blit(
            self.backButton,
            (self.screen_size[0]-self.backButtonSize,
             self.screen_size[1]-self.backButtonSize)
            )


    def drawBackground(self):
        """Clear the screen by re-drawing this application's background
        screen and adding the back button.
        """
        self.screen.blit(self.bg,(0,0))
        self.drawBackButton()
        self.repaint()

    def repaint(self):
        """ force the screen to repaint """
        pygame.display.flip()

    def processEvent(self,event):
        """process keyboard and mouse events.  This needs to be
        defined in a sub-class to be useful!
        """
        #print "appbase.processEvent()"
        pass

    def processDisplay(self,delay=0):
        """ process the display objects - this is the main activity
        of the application, and must be defined in a sub-class of this
        class.
        """
        #print "appbase.processDisplay()"
        pass


    def update(self,delay):
        """ Update all sprites given their specified speeds and positions
        """
        for sprite in self.SpriteList:
            sprite.update(delay*self.timeScale)


    def mainLoop(self):
        Clock = pygame.time.Clock()
        self.running = True
        act_delay = 0.0

        while self.running:
            # Process events 
            for event in pygame.event.get(): 
                if event.type == QUIT: 
                    print "%s: QUIT Event" % (self.__class__.__name__)
                    self.stop()
                    #self.running = False
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE or \
                            (os.name == 'nt' and event.key == K_F4) or \
                            (os.name == 'mac' and event.key == K_q):
                        print "%s: Escape Key" % (self.__class__.__name__)
                        self.stop()
                        #self.running = False
                    elif event.key == K_p and \
                            event.mod & KMOD_CTRL:
                        fname = "%s.bmp" \
                            % (self.__class__.__name__)
                        print "Saving Image as %s" % fname
                        pygame.image.save(self.screen, fname)
                    elif event.key == K_PAGEUP:
                        self.timeScale *= 2.
                    elif event.key == K_PAGEDOWN:
                        self.timeScale *= 0.5
                elif event.type == MOUSEBUTTONUP and \
                        event.button == 1:
                    if self.backButtonRect.collidepoint(event.pos):
                        print "backButtonPressed - Exiting!"
                        self.stop()
            
                self.processEvent(event)

            # Draw
            self.Sprites.clear(self.screen, self.bg)
            self.Sprites.update(act_delay)
            if (act_delay!=0):
                pygame.draw.rect(self.screen,(0,0,0),(0,0,100,80),0)
                self.screen.blit(
                    self.font18.render(
                        '%02d fps' % int(1.0/(act_delay/1000.)), 
                        True, (255,255,255)), 
                    (5, 0))
                self.screen.blit(
                    self.font18.render(
                        'TimeScale=%3.1f' % self.timeScale, 
                        True, (255,255,255)), 
                    (5, 20)
                                 )
            self.processDisplay(act_delay)
            dirty = self.Sprites.draw(self.screen)
            self.drawBackButton()
            #if len(self.Sprites) > 1000:
            pygame.display.flip()
            #else:
            #    pygame.display.update(dirty)

            # Manually collect garbage
            # gc.collect()

            # Set speed
            act_delay = Clock.tick(60)

        print "%s: End of Main Loop" % (self.__class__.__name__)
